﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Fakes;
using Microsoft.Practices.Unity;
using Microsoft.QualityTools.Testing.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sern.Abstracts.Tracker.DataContracts;
using Sern.Common;
using Sern.Common.Fakes;
using Sern.ServiceImplementation;
using Sern.ServiceImplementation.Fakes;
using Sern.ServiceImplementation.TrackerDefinition.Data;
using Sern.ServiceImplementation.TrackerDefinition.Service;

namespace Sern.Test.ServiceImplementation.TrackerDefinition.Service
{
    [Ignore]
    [Obsolete("Test listener must be started on and off by the host the inner class won't do that anymore - they'll also be stateless.")]
    [TestClass]
    // ReSharper disable InconsistentNaming
    public class TrackerHost_EndJobTracker
    // ReSharper restore InconsistentNaming
    {
        readonly List<ClientListenerModel> _createdListeners = new List<ClientListenerModel>();

        [TestInitialize]
        public void Init()
        {
            ComponentLocator.Reset();

            new Sern.ServiceImplementation.LocalRegistrar().Register(ComponentLocator.Unity);

            ComponentLocator.Unity.RegisterTestInstance("SampleHostName", "HostName");
            ComponentLocator.Unity.RegisterTestInstance<IEnumerable<string>>(new string[] { "Test", "Hosting New Tracker" }, "Keywords");
            ComponentLocator.Unity.RegisterTestInstance<string>("First tracker hosting test", "Description");

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<Client>());

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<ClientStatusInfo>());

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<Job>());

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<JobKeyword>());

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<KeyAtClientLog>());

            ComponentLocator.Unity.RegisterInstance<IListenerFactory>(
                new StubIListenerFactory
                {
                    CreateUriUriClientTypeObject = (baseUri, operationUri, clientType, instance)
                                                   =>
                    {
                        ComponentLocator.Unity.ResolveTest<Action<Uri, Uri, ClientType, object>>(
                            "CreateUriCalledEventHandler")
                            (baseUri, operationUri, clientType, instance);

                        return new Listener
                        {
                            Open = () =>
                                   ComponentLocator.Unity.ResolveTest<Action<Uri, Uri, ClientType, object>>(
                                       "OpenListenerCalledEventHandler")(baseUri, operationUri, clientType,
                                                                         instance),

                            Close = () =>
                                    ComponentLocator.Unity.ResolveTest<Action<Uri, Uri, ClientType, object>>(
                                        "CloseListenerCalledEventHandler")(baseUri, operationUri, clientType,
                                                                           instance),

                            Dispose = () => { }
                        };
                    }
                }
                );

            ComponentLocator.Unity.RegisterTestInstance<Action<Uri, Uri, ClientType, object>>(
                (baseUri, operationUri, clientType, instance) => _createdListeners.Add
                    (new ClientListenerModel
                    {
                        BaseUri = baseUri.AbsoluteUri,
                        OperationUri = operationUri.OriginalString,
                        ClientType = clientType,
                        ListenerState = ListenerState.Initialized,
                        SingletonInstance = instance
                    }), "CreateUriCalledEventHandler");

            ComponentLocator.Unity.RegisterTestInstance<Action<Uri, Uri, ClientType, object>>(
                (baseUri, operationUri, clientType, instance) => _createdListeners.Add
                    (new ClientListenerModel
                    {
                        BaseUri = baseUri.AbsoluteUri,
                        OperationUri = operationUri.OriginalString,
                        ClientType = clientType,
                        ListenerState = ListenerState.Opened,
                        SingletonInstance = instance
                    }), "OpenListenerCalledEventHandler");

            ComponentLocator.Unity.RegisterTestInstance<Action<Uri, Uri, ClientType, object>>(
                (baseUri, operationUri, clientType, instance) => _createdListeners.Add
                    (new ClientListenerModel
                    {
                        BaseUri = baseUri.AbsoluteUri,
                        OperationUri = operationUri.OriginalString,
                        ClientType = clientType,
                        ListenerState = ListenerState.Closed,
                        SingletonInstance = instance
                    }), "CloseListenerCalledEventHandler");

        }

        [TestMethod]
        public void TestListenersAreStartedThenClosed()
        {
            var trackerHost = new TrackerHost(ComponentLocator.Unity.ResolveTest<string>("HostName"));
            var jobRecords = ComponentLocator.Unity.Resolve<IRepository<Job>>().Records;

            trackerHost.Initialize();

            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.TrackerHost && l.ListenerState == ListenerState.Initialized));
            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.TrackerHost && l.ListenerState == ListenerState.Opened));
            //Check that the new tracker exists in the fake persistence
            //Check that listeners are fired in a way that makes sense.
            //Check that keywords are correct. (This could be delegated to another class!

            var jobId = Guid.NewGuid();
            trackerHost.StartANewJob(jobId, ComponentLocator.Unity.ResolveTest<IEnumerable<string>>("Keywords"),
                 ComponentLocator.Unity.ResolveTest<string>("Description"));


            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.Tracker && l.ListenerState == ListenerState.Initialized), "Tracker listener not initialized");
            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.Tracker && l.ListenerState == ListenerState.Opened), "Tracker listener not opened");

            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.TrackerTelemetry && l.ListenerState == ListenerState.Initialized), "Tracker telemetry not initialized");
            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.TrackerTelemetry && l.ListenerState == ListenerState.Opened), "Tracker telemetry not opened");

            Assert.IsTrue(jobRecords.Any(j => j.EndTime == null), "job must be marked as NOT ended.");

            trackerHost.EndAGivenJob(jobId);
            
            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.Tracker && l.ListenerState == ListenerState.Closed), "Tracker listener not closed");            
            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.TrackerTelemetry && l.ListenerState == ListenerState.Closed), "Tracker telemetry not closed");

            

            Assert.IsTrue(jobRecords.Any(j => j.EndTime != null), "job must be marked as having ended.");
        }
        
    }
}
